package com.winit.deploy.task.springBootTask;

import com.winit.common.util.ShellRunUtil;
import com.winit.common.util.SpringContextHolder;
import com.winit.core.server.factory.LinuxJumpServerFactory;
import com.winit.core.task.Task;
import com.winit.deploy.bean.WinitSpringBootInfo;
import com.winit.deploy.manager.DeployManager;
import com.winit.deploy.server.WinitJumpServer;
import com.winit.deploy.server.WinitSpringBootServer;
import com.winit.project.core.bean.PackageTypeEnum;
import com.winit.project.core.branch.Project;
import com.winit.project.util.ProjectUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

/**
 * 发布springboot应用准备阶段
 * 1、校验终端空间、工程发布使用目录是否存在
 * 2、校验配置文件是否正确
 * 3、将发布jar包和配置文件在本地或者跳板机打成压缩包，准备发布
 * 4、从本地或者跳板机推送发布包至终端
 * 5、校验终端发布包是否存在
 */
public class SpringBootPrepareTask extends Task {

    static final Logger logger = LoggerFactory.getLogger(SpringBootPrepareTask.class);

    /**
     * 跳板机
     * 用于推送jar包
     */
    private WinitJumpServer winitJumpServer = null;
    /**
     * 远程终端机,用于校验jar是否推送成功
     */
    private WinitSpringBootServer server;
    /**
     * 必传
     */
    private WinitSpringBootInfo info;

    /**
     * 使用beetle本机推送jar包
     *
     * @param taskId
     * @param expireTime
     */
    public SpringBootPrepareTask(String taskId, Integer expireTime, WinitSpringBootServer server, WinitSpringBootInfo info) {
        super(taskId, expireTime);
        this.server = server;
        this.info = info;
    }

    /**
     * 使用跳板机推送jar包
     *
     * @param taskId
     * @param expireTime
     * @param winitJumpServer
     */
    public SpringBootPrepareTask(String taskId, Integer expireTime, WinitSpringBootServer server, WinitJumpServer winitJumpServer, WinitSpringBootInfo info) {
        super(taskId, expireTime);
        this.server = server;
        this.winitJumpServer = winitJumpServer;
        this.info = info;
    }

    @Override
    public TaskStatus call() throws Exception {
        logger.info("com.winit.deploy.task.springBootTask.SpringBootPrepareTask#call start taskId=" + this.taskId);
        String projectName = this.info.getProjectName();
        String editionNum = this.info.getEditionNum();

        StringBuffer errorStr = new StringBuffer();

        //2.jar包临时存放目录是否存在
        try {
            String percent = this.server.getPercentOfSpace();
            if ("100".equals(percent)) {
                errorStr.append("<br>终端空间已满,请先清理后再进行发布!");
            }
        } catch (Exception e) {
            errorStr.append("<br>检验终端空间剩余,").append(e.getMessage());
        }
        try {
            this.server.isPathExist(this.info.getServerPath(), true, true);
        } catch (Exception e) {
            errorStr.append("<br>校验工程存放目录,").append(e.getMessage());
        }
        try {
            this.server.isPathExist(this.info.getBackUpDir(), true, true);
        } catch (Exception e) {
            errorStr.append("<br>校验工程备份目录,").append(e.getMessage());
        }
        try {
            this.server.isPathExist(this.info.getJarTempDir(), true, true);
        } catch (Exception e) {
            errorStr.append("<br>校验发布包临时存放目录,").append(e.getMessage());
        }
        //4.校验配置文件
        DeployManager deployManager = SpringContextHolder.getBean(DeployManager.class);
        try {
            deployManager.deployPrepare(this.info, this.taskId);
            //生成发布包  将jar包和配置文件压缩为tgz包
            if (this.winitJumpServer == null) {
                Project project = new Project(projectName, true);
                String warName = this.info.getWarName();
                String jarPath = ProjectUtil.getProjectFilePath(projectName) + editionNum + "/target/" + warName + ".jar";
                ProjectUtil.replaceConfigFile(PackageTypeEnum.SPRING_BOOT_JAR, ProjectUtil.getProjectFilePath(projectName) + editionNum + "/release" + "/" + this.taskId
                        , this.info.getJarPath().replace(warName + ".tgz", "")
                        , jarPath, warName, project.getProjectConfig().getConfigPath(), this.info.isVmEnv());
            }
        } catch (Exception e) {
            errorStr.append("<br>校验配置文件,").append(e.getMessage());
        }
        if (!StringUtils.isEmpty(errorStr.toString())) {
            throw new Exception(errorStr.toString());
        }

        //当前task发布使用的jar包存放目录
        String releaseTempPath = this.info.getJarPath().replace(this.info.getWarName() + ".tgz", "");
        try {
            if (this.winitJumpServer != null) {
                /**
                 * 1、推送配置文件包到跳板机
                 * 2、从跳板机推送配置文件包到终端
                 * 3、从跳板机推送发布包到终端
                 */
                //需要使用跳板机时,先将config包从本地推送到跳板机,然后再从跳板机推送至终端
                this.winitJumpServer.deldirs(releaseTempPath);
                this.winitJumpServer.mkdirs(releaseTempPath);
                //推送环境配置文件包至跳板机
                pushToJump(releaseTempPath);
                //在跳板机上生成发布jar包
                String editionPath = ProjectUtil.getProjectFilePath(projectName) + editionNum;
                this.winitJumpServer.createWarPackage(PackageTypeEnum.SPRING_BOOT_JAR, releaseTempPath, editionPath, this.taskId, this.info.getWarName(), "", "");
                //推送war包至终端机
                this.winitJumpServer.doPush(this.info.getJarPath(), this.info.getJarTempDir() + "/" + this.info.getWarName() + ".tgz"
                        , this.info.getServerIp(), this.info.getSshPort());
            } else {
                this.doPush();
            }

            this.server.isPathExist(this.info.getJarTempDir() +"/"+ this.info.getWarName() + ".tgz", false, false);

        } catch (Exception e) {
            throw e;
        } finally {
        }

        logger.info("com.winit.deploy.task.springBootTask.SpringBootPrepareTask#call end taskId=" + this.taskId);
        return TaskStatus.STATUS_SUCCESS;
    }

    /**
     * 从beetle本机推送
     *
     * @return
     * @throws Exception
     */
    private void doPush() throws Exception {
        String str = this.pushFromLocal(this.info.getSshPort(), this.info.getJarPath(),
                this.info.getUserName() + "@" + this.info.getServerIp() + ":" + this.info.getJarTempDir() + "/" + this.info.getWarName() + ".tgz");
        logger.info("SpringBootPrepareTask:从beetle本机推送发布包,返回:" + str);
        if (!StringUtils.isEmpty(str)) {
            throw new Exception("SpringBootPrepareTask:从beetle本机推送发布包失败," + str);
        }
    }

    private void pushToJump(String releaseTempPath) throws Exception {
        String evnConfigTarPath = ProjectUtil.getProjectFilePath(this.info.getProjectName()) +
                this.info.getEditionNum() + "/release/" + this.taskId + ".tgz";
        String level = this.winitJumpServer.getLevel();
        if ("1".equals(level)) {
            pushToLevelOneFromLocal(evnConfigTarPath, releaseTempPath, this.winitJumpServer.getIp()
                    , String.valueOf(this.winitJumpServer.getServerPort()));
        } else {
            WinitJumpServer levelOne = LinuxJumpServerFactory.getInstance().getParentServer(this.winitJumpServer.getIp());
            levelOne.deldirs(releaseTempPath);
            levelOne.mkdirs(releaseTempPath);
            pushToLevelOneFromLocal(evnConfigTarPath, releaseTempPath, levelOne.getIp(), String.valueOf(levelOne.getServerPort()));
            levelOne.doPush(releaseTempPath + this.taskId + ".tgz", releaseTempPath + "/", this.winitJumpServer.getIp()
                    , String.valueOf(this.winitJumpServer.getServerPort()));
        }
    }

    /**
     * 将环境配置文件压缩包推送至一级跳板机
     *
     * @param evnConfigTarPath 环境配置文件压缩包路径 在版本目录下
     * @param releaseTempPath  当前task发布包路径存放目录
     * @param ip
     * @param port
     * @throws Exception
     */
    private void pushToLevelOneFromLocal(String evnConfigTarPath, String releaseTempPath, String ip, String port) throws Exception {
        String str = this.pushFromLocal(port, evnConfigTarPath, this.info.getUserName() + "@" + ip + ":" + releaseTempPath);
        logger.info("SpringBootPrepareTask:从beetle本机推送配置文件包至跳板机,返回:" + str);
        if (!StringUtils.isEmpty(str)) {
            throw new Exception("SpringBootPrepareTask:从beetle本机推送配置文件包至跳板机失败," + str);
        }
    }

    private String pushFromLocal(String port, String fromPath, String toPath) {
        String[] param = new String[7];
        param[0] = "scp";
        param[1] = "-i";
        param[2] = this.info.getKeyFilePath();
        param[3] = "-P";
        param[4] = port;
        param[5] = fromPath;
        param[6] = toPath;
        String str = ShellRunUtil.runShell(param);
        logger.info("com.winit.deploy.task.springBootTask.SpringBootPrepareTask.pushFromLocal str=" + str);
        return str;
    }

}
